package com.course.finalproject.service;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.StatusLine;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.util.Log;

import com.course.finalproject.Constants;
import com.course.finalproject.model.CurrentWeather;
import com.course.finalproject.model.Weather;
import com.course.finalproject.model.WeatherForecast;

public class WundergroundWeatherRequest implements WeatherRequest {

	private static String API_KEY = "3388b5dbeb8fe22b";
	
	@Override
	public List<Weather> requestWeather(double lat, double lon, int days_count) {
		List<Weather> listWeathers = new ArrayList<Weather>();
		
		CurrentWeather currentWeather = requestCurrentWeather(lat, lon);
		if (currentWeather != null) {
			listWeathers.add(currentWeather);
			List<WeatherForecast> listExtWeathers = requestWeatherForecast(lat, lon, days_count);
			listWeathers.addAll(listExtWeathers);
		}

		return listWeathers;
	}
	
	/**
	 * Requests the weather forecast for a given number of days using wounderground.com API.
	 * 
	 * @param lat Latitude of the location to gets the weather.
	 * @param lon Longitude of the location to gets the weather.
	 * @param days_count Number of days to gets the forecast.
	 * @return The array of weather forecast for many days.
	 */
	public List<WeatherForecast> requestWeatherForecast(double lat, double lon, int days_count) {
		List<WeatherForecast> result = new ArrayList<WeatherForecast>();
		HttpClient httpclient = new DefaultHttpClient();
		String URL = "http://api.wunderground.com/api/" + API_KEY + "/forecast10day/q/" + lat + "," + lon + ".json";
		HttpResponse response = null;
		try {
			response = httpclient.execute(new HttpGet(URL));
			StatusLine statusLine = response.getStatusLine();
			if (statusLine.getStatusCode() == HttpStatus.SC_OK) {
				Log.d(Constants.LOG_TAG, "Request of weather forecast OK");
				ByteArrayOutputStream out = new ByteArrayOutputStream();
				response.getEntity().writeTo(out);
				out.close();
				String responseString = out.toString();
				result = parseWeatherForecastResponse(responseString, days_count);
			} else {
				Log.d(Constants.LOG_TAG, "Request of weather forecast failed ! HTTP status code: " + statusLine.getStatusCode());
				response.getEntity().getContent().close();
			}
		} catch (ClientProtocolException e) {
			Log.d(Constants.LOG_TAG, e.toString());
			e.printStackTrace();
		} catch (IOException e) {
			Log.d(Constants.LOG_TAG, e.toString());
			e.printStackTrace();
		} catch (IllegalStateException e) {
			Log.d(Constants.LOG_TAG, e.toString());
			e.printStackTrace();
		}
		
		return result;
	}

	/**
	 * Parse the weather forecast from wunderground.com API to get an array of weather.
	 * 
	 * @param response The Json string response of a weather forecast request.
	 * @param days_count The number of days to parse.
	 * @return The array of weather forecast corresponding on the parsed response.
	 */
	private List<WeatherForecast> parseWeatherForecastResponse(String response, int days_count) {
		List<WeatherForecast> result = new ArrayList<WeatherForecast>();
		try {
			JSONObject main = new JSONObject(response);
			JSONArray forecastArray = main.getJSONObject("forecast").getJSONObject("simpleforecast").getJSONArray("forecastday");
			for (int i = 0; i < forecastArray.length() && i < days_count; i++) {
				if (i!=0) {
					JSONObject local = forecastArray.getJSONObject(i);

					String weekday = local.getJSONObject("date").getString("weekday");
					String conditions = local.getString("conditions");
					String icon = local.getString("icon");
					int highCelsius = local.getJSONObject("high").getInt("celsius");
					int lowCelsius = local.getJSONObject("low").getInt("celsius");
					int highFahrenheit = local.getJSONObject("high").getInt("fahrenheit");
					int lowFahrenheit = local.getJSONObject("low").getInt("fahrenheit");
					int averageHumidity = local.getInt("avehumidity");
					int averageWindMph = local.getJSONObject("avewind").getInt("mph");
					int averageWindKph = local.getJSONObject("avewind").getInt("kph");
					String averageWindDir = local.getJSONObject("avewind").getString("dir");
					
					WeatherForecast weather = new WeatherForecast(	weekday, conditions, icon, highCelsius, lowCelsius, highFahrenheit,
																	lowFahrenheit, averageHumidity, averageWindMph, averageWindKph,
																	averageWindDir);
					result.add(weather);
				}
			}
		} catch (JSONException e) {
			Log.d(Constants.LOG_TAG, "Parsing weather forecast failed !");
			e.printStackTrace();
		}        
        
		return result;
	}


	/**
	 * Requests the current weather using wounderground.com API.
	 * 
	 * @param lat Latitude of the location to gets the weather.
	 * @param lon Longitude of the location to gets the weather.
	 * @return The current weather.
	 */
	public CurrentWeather requestCurrentWeather(double lat, double lon) {
		CurrentWeather result = null;
		HttpClient httpclient = new DefaultHttpClient();
		String URL = "http://api.wunderground.com/api/" + API_KEY + "/conditions/q/" + lat + "," + lon + ".json";
		HttpResponse response = null;
		try {
			response = httpclient.execute(new HttpGet(URL));
			StatusLine statusLine = response.getStatusLine();
			if (statusLine.getStatusCode() == HttpStatus.SC_OK) {
				Log.d(Constants.LOG_TAG, "Request of current weather OK");
				ByteArrayOutputStream out = new ByteArrayOutputStream();
				response.getEntity().writeTo(out);
				out.close();
				String responseString = out.toString();
				result = parseCurrentWeatherResponse(responseString);
			} else {
				Log.d(Constants.LOG_TAG, "Request of current weather failed ! HTTP status code: " + statusLine.getStatusCode());
				response.getEntity().getContent().close();
			}
		} catch (ClientProtocolException e) {
			Log.d(Constants.LOG_TAG, e.toString());
			e.printStackTrace();
		} catch (IOException e) {
			Log.d(Constants.LOG_TAG, e.toString());
			e.printStackTrace();
		} catch (IllegalStateException e) {
			Log.d(Constants.LOG_TAG, e.toString());
			e.printStackTrace();
		}
		
		return result;
	}
	
	/**
	 * Parse the current weather from wunderground.com API.
	 * 
	 * @param response The Json string response of a weather forecast request.
	 * @return The current weather corresponding on the parsed response.
	 */
	private CurrentWeather parseCurrentWeatherResponse(String response) {
		CurrentWeather result = null;
		try {
			JSONObject currentObservation = new JSONObject(response).getJSONObject("current_observation");
			// Parse.
			String condition = currentObservation.getString("weather");
			String icon = currentObservation.getString("icon");
			int cTemp = currentObservation.getInt("temp_c");
			int fTemp = currentObservation.getInt("temp_f");
			String relativeHumidity = currentObservation.getString("relative_humidity");
			int windMph = currentObservation.getInt("wind_mph");
			int windKph = currentObservation.getInt("wind_kph");
			String windDir = currentObservation.getString("wind_dir");
			String location = currentObservation.getJSONObject("display_location").getString("full");
			
			CurrentWeather currentWeather = new CurrentWeather(condition, icon, cTemp, fTemp, relativeHumidity,
															   windMph, windKph, windDir, location);
			// Set result.
			result = currentWeather;
		} catch (JSONException e) {
			Log.d(Constants.LOG_TAG, "Parsing weather forecast failed !");
			e.printStackTrace();
		}        
        
		return result;
	}
	
}
